#pragma once

#include<iostream>
#include<queue>
#include<pthread.h>
using namespace std;
pthread_mutex_t cout_mutex = PTHREAD_MUTEX_INITIALIZER;  

template<class T>
class BlockQueue
{
static const int defalutnum = 20;
public:
    BlockQueue(int max=defalutnum):_max(max)
    {
        pthread_mutex_init(&_mutex, nullptr);//初始化锁和条件变量
        pthread_cond_init(&_c_cond, nullptr);
        pthread_cond_init(&_p_cond, nullptr);
    }
    T pop()//拿任务
    {
        pthread_mutex_lock(&_mutex);
        while(q.size()==0)
        {
            pthread_cond_wait(&_c_cond,&_mutex);
        }
        T out=q.front();
        q.pop();
        pthread_cond_signal(&_p_cond);//唤醒生产者
        pthread_mutex_unlock(&_mutex);
        return out;
    }
    void push(const T&in)//生产任务
    {
        pthread_mutex_lock(&_mutex);
        while(q.size()==_max)
        {
            pthread_cond_wait(&_p_cond,&_mutex);//防止多生产者线程一起唤醒时，做检查，防止满了还抢消费者，循环检查代替if
        }
        q.push(in);
        pthread_cond_signal(&_c_cond);//唤醒消费者
        pthread_mutex_unlock(&_mutex);
    }
    ~BlockQueue()//释放锁变量
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_c_cond);
        pthread_cond_destroy(&_p_cond);
    }
private:
    queue<T> q;
    int _max;
    pthread_mutex_t _mutex;//锁
    pthread_cond_t _c_cond;//生产条件变量
    pthread_cond_t _p_cond;//消费条件变量
};
